package com.taxx.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Excel模板校验工具类
 *
 * @author taxx
 * @since 2024-01-01
 */
@Slf4j
public class ExcelTemplateValidator {

    /**
     * 校验收入信息Excel模板
     */
    public static ValidationResult validateIncomeTemplate(MultipartFile file) {
        ValidationResult result = new ValidationResult();

        try {
            // 校验文件基本信息
            if (!validateBasicInfo(file, result)) {
                return result;
            }

            // 校验表头
            List<String> expectedHeaders = Arrays.asList(
                    "否办理市场主体登记",
                    "统一社会信用代码", "纳税人名称", "商户ID", "商户名称", "收入总额（已取得登记证照的销售货物取得的收入）",
                    "退款金额（已取得登记证照的销售货物取得的收入）", "收入总额（已取得登记证照的销售无形资产取得的收入）",
                    "退款金额（已取得登记证照的销售无形资产取得的收入）", "收入总额（已取得登记证照的销售服务取得的收入）",
                    "退款金额（已取得登记证照的销售服务取得的收入）", "收入总额（未取得登记证照）",
                    "退款金额（未取得登记证照）", "收入净额销售货物（未取得登记证照）",
                    "收入净额货物运输服务（未取得登记证照）", "收入净额劳务报酬（未取得登记证照）",
                    "收入净额稿酬（未取得登记证照）", "收入净额特许权使用费（未取得登记证照）",
                    "从事其他网络交易活动取得的收入（净额）", "支付给平台的佣金、服务费合计金额",
                    "交易（订单）数量（笔）"
            );

            if (!validateHeaders(file, expectedHeaders, result)) {
                return result;
            }

            // 校验数据行
            if (!validateDataRows(file, "income", result)) {
                return result;
            }

            result.setValid(true);
            result.setMessage("收入信息Excel模板校验通过");

        } catch (Exception e) {
            log.error("收入信息Excel模板校验失败", e);
            result.setValid(false);
            result.setMessage("模板校验失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 校验身份信息Excel模板
     */
    public static ValidationResult validateIdentityTemplate(MultipartFile file) {
        ValidationResult result = new ValidationResult();

        try {
            // 校验文件基本信息
            if (!validateBasicInfo(file, result)) {
                return result;
            }

            // 校验表头
            List<String> expectedHeaders = Arrays.asList(
                    "否办理市场主体登记", "统一社会信用代码", "纳税人名称", "详细地址",
                    "商户ID", "商户名称", "网址", "联系人", "联系电话", "经营开始时间",
                    "操作类型代码", "专业服务机构标识", "结算账户信息"
            );

            if (!validateHeaders(file, expectedHeaders, result)) {
                return result;
            }

            // 校验数据行
            if (!validateDataRows(file, "identity", result)) {
                return result;
            }

            result.setValid(true);
            result.setMessage("身份信息Excel模板校验通过");

        } catch (Exception e) {
            log.error("身份信息Excel模板校验失败", e);
            result.setValid(false);
            result.setMessage("模板校验失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 校验平台信息Excel模板
     */
    public static ValidationResult validatePlatformTemplate(MultipartFile file) {
        ValidationResult result = new ValidationResult();

        try {
            // 校验文件基本信息
            if (!validateBasicInfo(file, result)) {
                return result;
            }

            // 校验表头
            List<String> expectedHeaders = Arrays.asList(
                    "纳税人名称", "统一社会信用代码", "平台名称", "平台ID",
                    "经营开始时间", "经营退出时间", "操作类型代码"
            );

            if (!validateHeaders(file, expectedHeaders, result)) {
                return result;
            }

            // 校验数据行
            if (!validateDataRows(file, "platform", result)) {
                return result;
            }

            result.setValid(true);
            result.setMessage("平台信息Excel模板校验通过");

        } catch (Exception e) {
            log.error("平台信息Excel模板校验失败", e);
            result.setValid(false);
            result.setMessage("模板校验失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 校验文件基本信息
     */
    private static boolean validateBasicInfo(MultipartFile file, ValidationResult result) {
        // 检查文件是否为空
        if (file == null || file.isEmpty()) {
            result.setValid(false);
            result.setMessage("上传的文件不能为空");
            return false;
        }

        // 检查文件大小（限制为10MB）
        if (file.getSize() > 10 * 1024 * 1024) {
            result.setValid(false);
            result.setMessage("文件大小不能超过10MB");
            return false;
        }

        // 检查文件扩展名
        String fileName = file.getOriginalFilename();
        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
            result.setValid(false);
            result.setMessage("只支持.xlsx和.xls格式的Excel文件");
            return false;
        }

        return true;
    }

    /**
     * 校验表头
     */
    private static boolean validateHeaders(MultipartFile file, List<String> expectedHeaders, ValidationResult result) {
        try {
            // 使用包装类来存储表头，解决内部类访问问题
            final List<String> actualHeaders = new ArrayList<>();
            
            log.info("开始校验表头，期望表头数量：{}", expectedHeaders.size());
            log.info("期望表头：{}", String.join(", ", expectedHeaders));
            
            // 使用Map<Integer, String>来读取表头，这是EasyExcel的默认类型
            EasyExcel.read(file.getInputStream())
                .sheet()
                .headRowNumber(0) // 明确指定第一行是表头
                .registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
                    @Override
                    public void invoke(Map<Integer, String> data, AnalysisContext context) {
                        log.info("读取到行数据，行索引：{}，数据：{}", context.readRowHolder().getRowIndex(), data);
                        
                        // 读取第一行作为表头
                        if (context.readRowHolder().getRowIndex() == 0) {
                            log.info("读取到第一行数据：{}", data);
                            for (int i = 0; i < expectedHeaders.size(); i++) {
                                String cellValue = data.getOrDefault(i, "");
                                String trimmedValue = cellValue != null ? cellValue.trim() : "";
                                actualHeaders.add(trimmedValue);
                                log.info("第{}列：原始值='{}'，处理后='{}'", i + 1, cellValue, trimmedValue);
                            }
                        }
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        log.info("表头读取完成，实际读取到的表头：{}", String.join(", ", actualHeaders));
                    }
                })
                .doRead();

            log.info("实际读取到的表头：{}", String.join(", ", actualHeaders));
            log.info("实际表头数量：{}", actualHeaders.size());

            // 校验表头数量
            if (actualHeaders.size() != expectedHeaders.size()) {
                result.setValid(false);
                result.setMessage("表头列数不足，期望" + expectedHeaders.size() + "列，实际" + actualHeaders.size() + "列");
                return false;
            }

            // 校验表头内容
            for (int i = 0; i < expectedHeaders.size(); i++) {
                String expected = expectedHeaders.get(i);
                String actual = actualHeaders.get(i);

                if (!expected.equals(actual)) {
                    result.setValid(false);
                    result.setMessage("第" + (i + 1) + "列表头不匹配，期望：" + expected + "，实际：" + actual);
                    log.error("表头不匹配：第{}列，期望：'{}'，实际：'{}'", i + 1, expected, actual);
                    return false;
                }
            }

            log.info("表头校验通过");
            return true;

        } catch (Exception e) {
            log.error("校验表头失败", e);
            result.setValid(false);
            result.setMessage("校验表头失败：" + e.getMessage());
            return false;
        }
    }

    /**
     * 校验数据行
     */
    private static boolean validateDataRows(MultipartFile file, String type, ValidationResult result) {
        try {
            // 使用包装类来存储行数，解决内部类访问问题
            final int[] rowCount = {0};
            
            log.info("开始校验数据行，类型：{}", type);
            
            // 使用与表头读取一致的方式
            EasyExcel.read(file.getInputStream())
                .sheet()
                .headRowNumber(0) // 明确指定第一行是表头
                .registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
                    @Override
                    public void invoke(Map<Integer, String> data, AnalysisContext context) {
                        // 跳过第一行（索引为0），从第二行开始计算
                        if (context.readRowHolder().getRowIndex() > 0) {
                            rowCount[0]++;
                            if (rowCount[0] <= 3) { // 只记录前3行用于调试
                                log.debug("第{}行数据：{}", context.readRowHolder().getRowIndex() + 1, data);
                            }
                        }
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        // 不需要处理
                    }
                })
                .doRead();

            log.info("数据行校验完成，总数据行数：{}", rowCount[0]);

            if (rowCount[0] == 0) {
                result.setValid(false);
                result.setMessage("Excel文件中没有数据行");
                return false;
            }

            if (rowCount[0] > 1000000) {
                result.setValid(false);
                result.setMessage("数据行数过多，最多支持1000000行");
                return false;
            }

            log.info("数据行校验通过");
            return true;

        } catch (Exception e) {
            log.error("校验数据行失败", e);
            result.setValid(false);
            result.setMessage("校验数据行失败：" + e.getMessage());
            return false;
        }
    }

    /**
     * 校验结果类
     */
    @Setter
    @Getter
    public static class ValidationResult {
        private boolean valid;
        private String message;
        private List<String> details;
        public ValidationResult() {
            this.details = new ArrayList<>();
        }

    }
}
